package woaini.fenger.bots.opq.bot.adapter;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import woaini.fenger.bots.opq.bot.internal.OpqInternal;
import woaini.fenger.bots.opq.dto.*;
import woaini.fenger.bots.opq.dto.OpqRequest.CgiRequest;
import woaini.fenger.bots.opq.dto.OpqRequest.CgiRequest.AtUinLists;
import woaini.fenger.bots.opq.dto.OpqRequest.CgiRequest.Images;
import woaini.fenger.bots.opq.dto.OpqRequest.CgiRequest.Voice;
import woaini.fenger.core.bot.base.Bot;
import woaini.fenger.core.bot.base.IBotAdapter;
import woaini.fenger.core.bot.enums.*;
import woaini.fenger.core.bot.event.*;
import woaini.fenger.core.bot.event.message.GroupMessageEvent;
import woaini.fenger.core.bot.event.message.PrivateMessageEvent;
import woaini.fenger.core.bot.event.message.impl.*;
import woaini.fenger.core.bot.event.message.impl.Record;
import woaini.fenger.core.bot.id.ID;

/**
 * OPQ机器人适配器实施
 *
 * @see woaini.fenger.bots.opq.bot.adapter.OpqBotAdapterImpl
 * @author yefeng {@code @Date} 2023-05-16 16:50:39
 */
@Slf4j
public class OpqBotAdapterImpl extends IBotAdapter {

  /**
   * @see Map<PostTypeEnums, List<String>> 时间类型映射
   */
  private static final Map<PostTypeEnums, List<String>> POSTTYPE_EVENT_MAP = new HashMap<>(4);

  /**
   * @see Map<Integer, String> 消息子类型映射
   */
  private static final Map<Integer, PrivateMessageSubType> PRIVATE_MESSAGE_SUBTYPE_MAP =
      new HashMap<>(3);

  private static final Map<Integer, PrivateMessageSubType> GROUP_MESSAGE_SUBTYPE_MAP =
      new HashMap<>(3);

  static {
    POSTTYPE_EVENT_MAP.put(
        PostTypeEnums.message, List.of("ON_EVENT_GROUP_NEW_MSG", "ON_EVENT_FRIEND_NEW_MSG"));
    POSTTYPE_EVENT_MAP.put(PostTypeEnums.notice, List.of());
    POSTTYPE_EVENT_MAP.put(PostTypeEnums.request, List.of());
    POSTTYPE_EVENT_MAP.put(PostTypeEnums.meta_event, List.of());

    // 消息 子消息类型进行转换 3私聊 2群组 1好友
    PRIVATE_MESSAGE_SUBTYPE_MAP.put(1, PrivateMessageSubType.other);
    PRIVATE_MESSAGE_SUBTYPE_MAP.put(2, PrivateMessageSubType.group);
    PRIVATE_MESSAGE_SUBTYPE_MAP.put(3, PrivateMessageSubType.friend);

    //
  }

  public OpqBotAdapterImpl(Bot bot) {
    super(bot);
    this.internal = new OpqInternal(bot);
  }

  @Override
  public BaseEvent decode(ConnectType connectType, String rawString) {
    // 解析ws_client的
    if (connectType.equals(ConnectType.WS_CLIENT)) {
      OpqWsResponse wsResponse = JSONObject.parseObject(rawString, OpqWsResponse.class);

      BaseEvent baseEvent = decodBaseEvent(wsResponse);
      if (baseEvent == null) {
        log.warn("事件不存在");
        return null;
      }
      PostTypeEnums postType = baseEvent.getPostType();
      switch (postType) {
        case message:
          {
            return decodeMessage(baseEvent, wsResponse);
          }
        default:
          {
            log.warn("暂不支持:{}", postType);
          }
      }
    } else {
      log.warn("暂不支持:{}", connectType);
    }

    return null;
  }

  /**
   * @MethodName getPostTypeEnums
   *
   * @param eventName 事件名称
   * @author yefeng {@date 2024-01-23 11:18:31}
   * @since 1.0
   * @return {@link PostTypeEnums } 获取POST类型枚举
   */
  private PostTypeEnums getPostTypeEnums(String eventName) {
    for (Map.Entry<PostTypeEnums, List<String>> entry : POSTTYPE_EVENT_MAP.entrySet()) {
      if (entry.getValue().contains(eventName)) {
        return entry.getKey();
      }
    }
    return null;
  }

  /**
   * @MethodName buildMessage
   *
   * @param msgBody 消息身躯
   * @author yefeng {@date 2024-01-23 14:38:01}
   * @since 1.0
   * @return {@link Messages } 构建消息
   *     <p>//0为单一或复合类型消息(文字 At 图片 自由组合) //12 Xml消息 19 Video消息 51 JSON卡片消息
   */
  private Messages buildMessage(OpqResponse.MsgBody msgBody) {
    Messages builder = Messages.builder();
    if (msgBody == null){
      return builder;
    }

    Integer subMsgType = msgBody.getSubMsgType();
    String content = msgBody.getContent();
    if (subMsgType == 0) {
      // 移出at的东西
      content = content.replaceAll("@\\S+ ", "");
      builder.text(content);
    }
    // 获取是否存在at
    List<OpqAtUinList> atUinLists = msgBody.getAtUinLists();
    if (CollUtil.isNotEmpty(atUinLists)) {
      for (OpqAtUinList atUinList : atUinLists) {
        Long uin = atUinList.getUin();
        builder.at(ID.of(uin));
      }
    }
    // 解析图片内容
    List<OpqImages> images = msgBody.getImages();
    if (CollUtil.isNotEmpty(images)) {
      for (OpqImages opqImages : images) {
        Image image = new Image(opqImages.getUrl());
        image.getData().setUrl(opqImages.getUrl());
        builder.add(image);
      }
    }
    // 解析视频内容 TODO 暂时不进行 发送的还好 接收没必要

    // 解析音频内容

    return builder;
  }

  /**
   * @MethodName decodeMessage
   *
   * @param baseEvent 基本事件
   * @param wsResponse WS响应
   * @author yefeng {@date 2024-01-23 11:59:48}
   * @since 1.0
   * @return {@link BaseEvent } 对消息进行解码
   */
  private BaseEvent decodeMessage(BaseEvent baseEvent, OpqWsResponse wsResponse) {

    String eventName = wsResponse.getCurrentPacket().getEventName();
    OpqResponse.MsgHead msgHead = wsResponse.getCurrentPacket().getEventData().getMsgHead();
    OpqResponse.MsgBody msgBody = wsResponse.getCurrentPacket().getEventData().getMsgBody();

    switch (eventName) {
      case "ON_EVENT_GROUP_NEW_MSG":
        {
          GroupMessageEvent messageEvent = new GroupMessageEvent();
          // TODO 默认都是正常消息
          messageEvent.setSubType(GroupMessageSubType.normal);
          BeanUtil.copyProperties(baseEvent, messageEvent);
          Integer groupCode = msgHead.getGroupInfo().getGroupCode();
          messageEvent.setGroupId(ID.of(groupCode));
          messageEvent.setMessageId(String.valueOf(msgHead.getMsgUid()));
          messageEvent.setUserId(ID.of(msgHead.getFromUid()));
          messageEvent.setMessage(buildMessage(msgBody));
          messageEvent.setRawMessage(msgBody != null ?msgBody.getContent() : "");
          messageEvent.setAnonymous(new MessageAnonymous());
          return messageEvent;
        }
      case "ON_EVENT_FRIEND_NEW_MSG":
        {
          PrivateMessageEvent messageEvent = new PrivateMessageEvent();
          BeanUtil.copyProperties(baseEvent, messageEvent);
          // 3私聊 2群组 1好友
          int fromType = msgHead.getFromType();
          messageEvent.setSubType(PRIVATE_MESSAGE_SUBTYPE_MAP.get(fromType));
          messageEvent.setMessageId(String.valueOf(msgHead.getMsgUid()));
          messageEvent.setUserId(ID.of(msgHead.getFromUid()));
          messageEvent.setMessage(buildMessage(msgBody));
          messageEvent.setRawMessage(msgBody != null ?msgBody.getContent() : "");
          return messageEvent;
        }
      default:
        return null;
    }
  }

  private BaseEvent decodBaseEvent(OpqWsResponse wsResponse) {

    String eventName = wsResponse.getCurrentPacket().getEventName();
    // 查找对应的
    PostTypeEnums postTypeEnums = getPostTypeEnums(eventName);
    if (postTypeEnums == null) {
      log.warn("未解析的事件类型:{}", eventName);
      return null;
    }
    // 基础事件
    BaseEvent baseEvent = new BaseEvent();
    OpqResponse.MsgHead msgHead = wsResponse.getCurrentPacket().getEventData().getMsgHead();

    // 时间戳
    int time = msgHead.getMsgTime();
    baseEvent.setTime((long) time);
    int id = wsResponse.getCurrentQQ();
    baseEvent.setSelfId(ID.of(id));
    baseEvent.setPostType(postTypeEnums);

    MessageSender sender = new MessageSender();
    sender.setUserId(ID.of(msgHead.getSenderUin()));
    sender.setNickname(msgHead.getSenderNick());
    sender.setName(sender.getNickname());
    sender.setSex(SexEnums.unknown);

    OpqResponse.MsgHead.GroupInfo groupInfo = msgHead.getGroupInfo();

    if (groupInfo != null) {
      sender.setCard(groupInfo.getGroupCard());
      sender.setAge(0);
      sender.setArea("");
      sender.setLevel(String.valueOf(groupInfo.getGroupLevel()));
      sender.setRole(null);
      sender.setTitle("");
      sender.setGroupId(ID.of(groupInfo.getGroupCode()));
    }
    baseEvent.setSender(sender);
    return baseEvent;
  }

  @Override
  public void sendPrivateMessage(ID userId, Messages message, boolean autoEscape) {
    OpqInternal opqInternal = (OpqInternal) this.internal;
    opqInternal.sendMessage(buildRequest(null, userId, message));
  }

  @Override
  public void sendGroupMsg(ID groupId, Messages message, boolean autoEscape) {
    OpqInternal opqInternal = (OpqInternal) this.internal;
    opqInternal.sendMessage(buildRequest(groupId, null, message));
  }

  @Override
  public void sendMessage(
      String messageType, ID userId, ID groupId, Messages messages, boolean autoEscape) {
    OpqInternal opqInternal = (OpqInternal) this.internal;
    if ("private".equals(messageType)){
      opqInternal.sendMessage(buildRequest(null, userId, messages));
    }else {
      opqInternal.sendMessage(buildRequest(groupId, null, messages));
    }
  }

  public OpqRequest buildRequest(ID groupId, ID userId, Messages message) {
    OpqRequest opqRequest = new OpqRequest();
    opqRequest.setCgiCmd("MessageSvc.PbSendMsg");

    CgiRequest cgiRequest = new CgiRequest();
    cgiRequest.setToUin(0L);
    // 3私聊 2群组 1好友

    int toType = 0;
    long tUin = 0;

    if (groupId != null && userId != null) {
      toType = 3;
      tUin = userId.getLongValue();
    } else if (groupId == null) {
      toType = 1;
      tUin = userId.getLongValue();
    } else {
      toType = 2;
      tUin = groupId.getLongValue();
    }
    cgiRequest.setToUin(tUin);
    cgiRequest.setToType(toType);

    List<Segment> elements = message.getElements();
    ArrayList<AtUinLists> atUinLists = new ArrayList<>();
    ArrayList<Images> images = new ArrayList<>();

    OpqInternal opqInternal = (OpqInternal) this.internal;

    // 进行解析
    for (Segment element : elements) {
      if (element instanceof Text text) {
        cgiRequest.setContent(text.getData().getText());
      } else if (element instanceof At at) {
        AtUinLists atUin = new AtUinLists();
        atUin.setUin(at.getData().getQq().getLongValue());
        atUinLists.add(atUin);
      } else if (element instanceof Image image) {
        int CommandId = 1;
        if (toType == 2) {
          CommandId = 2;
        }
        OpqUploadResponse response =
            opqInternal.upload(
                CommandId, image.getFilePath(), image.getFileUrl(), image.getBase64());
        OpqRequest.CgiRequest.Images opqImages = new OpqRequest.CgiRequest.Images();
        String fileMd5 = response.getResponseData().getFileMd5();
        Integer fileSize = response.getResponseData().getFileSize();
        opqImages.setFileMd5(fileMd5);
        opqImages.setFileSize(fileSize);
        images.add(opqImages);
      } else if (element instanceof Record record) {
        int CommandId = 26;
        if (toType == 2) {
          CommandId = 29;
        }
        // 语音
        OpqUploadResponse response =
            opqInternal.upload(
                CommandId, record.getFilePath(), record.getFileUrl(), record.getBase64());

        OpqRequest.CgiRequest.Voice opqVoice = new OpqRequest.CgiRequest.Voice();

        String fileMd5 = response.getResponseData().getFileMd5();
        Integer fileSize = response.getResponseData().getFileSize();
        String fileToken = response.getResponseData().getFileToken();
        opqVoice.setFileMd5(fileMd5);
        opqVoice.setFileSize(fileSize);
        opqVoice.setFileToken(fileToken);
        cgiRequest.setVoice(opqVoice);
      } else if (element instanceof Video video) {
        // 暂时不支持视频
      }
    }
    cgiRequest.setAtUinLists(atUinLists);
    cgiRequest.setImages(images);
    opqRequest.setCgiRequest(cgiRequest);
    return opqRequest;
  }
}
